package com.example.learnandroid;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;

import sysu.ss.xu.FFmpeg;

import com.churnlabs.ffmpegsample.MainActivity;
import android.app.Activity;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.media.CamcorderProfile;
import android.media.MediaMetadataRetriever;
import android.media.MediaRecorder;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageButton;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
import android.widget.RadioGroup.OnCheckedChangeListener;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import android.widget.Toast;

public class MakeGIF_v2 extends Activity {

	private Camera myCamera;
	private MyCameraSurfaceView myCameraSurfaceView;
	private MediaRecorder mediaRecorder;
	private ArrayList<Bitmap> lBitmap;
	private Button startButton,numFrame1,numFrame2,frameSize1,frameSize2;
	private boolean recording;
	private TextView tv_time;
	private CameraTime cam_th;
	private ProgressDialog progressDialog;
	private ImageButton btn_setting;
	private final Context context = this;
	private int camera_time;

	private RadioGroup radioCamGroup;
	private RadioButton radioCamButton;
	private int numberCam;
	private int numberFrames;
	private boolean frameSmall;
	private SeekBar seekbar;
	private int progressSeekBar;
	private TextView setting_tv1;
	
	private int time_sleep;

	private int cameraID; // 0 -> front ; 1 -> back

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
				WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.makegif_v2);

		initParameter();
		cameraInit();
		addListenerOnButton();

	}

	private void initParameter() {
		progressSeekBar = 25;
		time_sleep = 333;
		numberFrames = 20;
		camera_time = numberFrames;
		frameSmall = true;
		cameraID = 1;
		tv_time = (TextView) findViewById(R.id.tv_camera);
		tv_time.setText(String.valueOf(camera_time));
		recording = false;
		radioCamGroup = (RadioGroup) findViewById(R.id.radioCam);
		radioCamGroup.setOnCheckedChangeListener(new OnCheckedChangeListener() {

			@Override
			public void onCheckedChanged(RadioGroup group, int checkedId) {
				releaseCamera();
				if (checkedId == R.id.radioFront) {// front camera
					cameraID = 0;
					cameraInit2();
				} else if (checkedId == R.id.radioBack) {// back camera
					cameraID = 1;
					cameraInit2();
				}
			}
		});

		Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
		numberCam = Camera.getNumberOfCameras();
	}

	private void cameraInit() {
		// Get Camera for preview
		myCamera = getCameraInstance();
		if (myCamera == null) {
			Toast.makeText(MakeGIF_v2.this, "Fail to get Camera",
					Toast.LENGTH_LONG).show();
		}

		myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
		FrameLayout myCameraPreview = (FrameLayout) findViewById(R.id.videoview);
		myCameraPreview.addView(myCameraSurfaceView);
	}

	private void cameraInit2() {
		// Get Camera for preview
		myCamera = getCameraInstance();
		if (myCamera == null) {
			Toast.makeText(MakeGIF_v2.this, "Fail to get Camera",
					Toast.LENGTH_LONG).show();
		}

		myCameraSurfaceView = new MyCameraSurfaceView(this, myCamera);
		FrameLayout myCameraPreview = (FrameLayout) findViewById(R.id.videoview);
		myCameraPreview.removeAllViews();
		myCameraPreview.addView(myCameraSurfaceView);
	}

	private void addListenerOnButton() {
		startButton = (Button) findViewById(R.id.startButton);
		btn_setting = (ImageButton) findViewById(R.id.btn_setting);
		startButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (recording) {
					// stop recording and release camera
					mediaRecorder.stop(); // stop the recording
					releaseMediaRecorder(); // release the MediaRecorder object

					// finish();
				} else {

					// Release Camera before MediaRecorder start
					releaseCamera();

					if (!prepareMediaRecorder()) {
						Toast.makeText(MakeGIF_v2.this,
								"Fail in prepareMediaRecorder()!\n - Ended -",
								Toast.LENGTH_LONG).show();
						finish();
					}

					mediaRecorder.start();
					recording = true;
					startButton.setVisibility(View.INVISIBLE);
					cam_th = new CameraTime();
					cam_th.start();
				}
			}
		});

		btn_setting.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Dialog dialog = new Dialog(context);
				dialog.setContentView(R.layout.layout_settings);
				dialog.setTitle("Settings");
				
				setListenerOnSettings(dialog);
				
				dialog.show();
			}
		});

	}
	
	private void setListenerOnSettings(Dialog dialog){
		setting_tv1 = (TextView) dialog.findViewById(R.id.setting_tv_1);
		numFrame1 = (Button) dialog.findViewById(R.id.setting_btn1);
		numFrame2 = (Button) dialog.findViewById(R.id.setting_btn2);
		frameSize1 = (Button) dialog.findViewById(R.id.setting_btn3);
		frameSize2 = (Button) dialog.findViewById(R.id.setting_btn4);
		
		float value = 0.9f*progressSeekBar/100f + 0.1f;
    	setting_tv1.setText("Auto speed: "+String.format("%.02f", value)+"sec per frame");
    	
    	if(numberFrames == 20){
    		numFrame1.setTextColor(this.getResources().getColor(R.color.red_color));
    		numFrame2.setTextColor(this.getResources().getColor(R.color.black_color));
    	}else{
    		numFrame2.setTextColor(this.getResources().getColor(R.color.red_color));
    		numFrame1.setTextColor(this.getResources().getColor(R.color.black_color));
    	}
    	
    	if(frameSmall == true){
    		frameSize1.setTextColor(this.getResources().getColor(R.color.red_color));
    		frameSize2.setTextColor(this.getResources().getColor(R.color.black_color));
    	}
    	else{
    		frameSize2.setTextColor(this.getResources().getColor(R.color.red_color));
    		frameSize1.setTextColor(this.getResources().getColor(R.color.black_color));
    	}
    	
		seekbar = (SeekBar) dialog.findViewById(R.id.setting_seekbar);
		seekbar.setProgress(progressSeekBar);
		seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
 
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser){
            	progressSeekBar = progress;
            	float value = 0.9f*progress/100f + 0.1f;
            	setting_tv1.setText("Auto speed: "+String.format("%.02f", value)+"sec per frame");
            	time_sleep = (int)(value*1000);
            }
 
            public void onStartTrackingTouch(SeekBar seekBar) {
                // TODO Auto-generated method stub
            }
 
            public void onStopTrackingTouch(SeekBar seekBar) {
                
            }
        });
		
		numFrame1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				numberFrames = 20;
				tv_time.setText(String.valueOf(numberFrames));
				camera_time = numberFrames;
				numFrame1.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.red_color));
	    		numFrame2.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.black_color));
			}
		});
		
		numFrame2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				numberFrames = 30;
				tv_time.setText(String.valueOf(numberFrames));
				camera_time = numberFrames;
				numFrame2.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.red_color));
	    		numFrame1.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.black_color));
			}
		});
		
		frameSize1.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				frameSmall = true;
				frameSize1.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.red_color));
				frameSize2.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.black_color));
			}
		});
		
		frameSize2.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View arg0) {
				frameSmall = false;
				frameSize2.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.red_color));
				frameSize1.setTextColor(MakeGIF_v2.this.getResources().getColor(R.color.black_color));
			}
		});
		
	}
	
	private Camera getCameraInstance() {
		Camera c = null;
		try {
			if (numberCam == 0) {

			} else if (numberCam == 1) {
				c = Camera.open(0);
			} else {
				if (cameraID == 1) {
					c = Camera.open();
				} else {
					Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
					for (int camIdx = 0; camIdx < numberCam; camIdx++) {
						Camera.getCameraInfo(camIdx, cameraInfo);
						if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
							try {
								c = Camera.open(camIdx);
							} catch (RuntimeException e) {
								Log.e("USER_TAG",
										"Camera failed to open: "
												+ e.getLocalizedMessage());
							}
						}

					}
				}

			}

		} catch (Exception e) {
			// Camera is not available (in use or does not exist)
		}
		return c; // returns null if camera is unavailable
	}

	private boolean prepareMediaRecorder() {
		myCamera = getCameraInstance();
		mediaRecorder = new MediaRecorder();

		myCamera.unlock();
		mediaRecorder.setCamera(myCamera);

		mediaRecorder.setAudioSource(MediaRecorder.AudioSource.CAMCORDER);
		mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
		// mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);

		mediaRecorder.setProfile(CamcorderProfile
				.get(CamcorderProfile.QUALITY_HIGH));
		mediaRecorder.setOutputFile("/sdcard/myvideo.mp4");
		mediaRecorder.setVideoSize(480, 320);
		mediaRecorder.setVideoFrameRate(3);

		mediaRecorder.setPreviewDisplay(myCameraSurfaceView.getHolder()
				.getSurface());

		try {
			mediaRecorder.prepare();
		} catch (IllegalStateException e) {
			releaseMediaRecorder();
			return false;
		} catch (IOException e) {
			releaseMediaRecorder();
			return false;
		}
		return true;

	}

	@Override
	protected void onPause() {
		super.onPause();
		releaseMediaRecorder(); // if you are using MediaRecorder, release it
								// first
		releaseCamera(); // release the camera immediately on pause event
	}

	private void releaseMediaRecorder() {
		if (mediaRecorder != null) {
			mediaRecorder.reset(); // clear recorder configuration
			mediaRecorder.release(); // release the recorder object
			mediaRecorder = null;
			myCamera.lock(); // lock camera for later use
		}
	}

	private void releaseCamera() {
		if (myCamera != null) {
			myCamera.release(); // release the camera for other applications
			myCamera = null;
		}
	}

	public class MyCameraSurfaceView extends SurfaceView implements
			SurfaceHolder.Callback {

		private SurfaceHolder mHolder;
		private Camera mCamera;

		@SuppressWarnings("deprecation")
		public MyCameraSurfaceView(Context context, Camera camera) {
			super(context);
			mCamera = camera;

			// Install a SurfaceHolder.Callback so we get notified when the
			// underlying surface is created and destroyed.
			mHolder = getHolder();
			mHolder.addCallback(this);
			// deprecated setting, but required on Android versions prior to 3.0
			mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
		}

		@Override
		public void surfaceChanged(SurfaceHolder holder, int format,
				int weight, int height) {
			// If your preview can change or rotate, take care of those events
			// here.
			// Make sure to stop the preview before resizing or reformatting it.

			if (mHolder.getSurface() == null) {
				// preview surface does not exist
				return;
			}

			// stop preview before making changes
			try {
				mCamera.stopPreview();
			} catch (Exception e) {
				// ignore: tried to stop a non-existent preview
			}

			// make any resize, rotate or reformatting changes here
			/*
			 * Camera.Parameters parameters = mCamera.getParameters();
			 * List<Camera.Size> previewSizes =
			 * parameters.getSupportedPreviewSizes(); Camera.Size previewSize =
			 * previewSizes.get(0); parameters.setPreviewSize(previewSize.width,
			 * previewSize.height); mCamera.setParameters(parameters);
			 */
			// start preview with new settings
			try {
				mCamera.setPreviewDisplay(mHolder);
				mCamera.startPreview();

			} catch (Exception e) {
			}
		}

		@Override
		public void surfaceCreated(SurfaceHolder holder) {
			// The Surface has been created, now tell the camera where to draw
			// the preview.
			try {

				mCamera.setPreviewDisplay(holder);
				mCamera.startPreview();
			} catch (IOException e) {
			}
		}

		@Override
		public void surfaceDestroyed(SurfaceHolder holder) {
			mCamera.release();

		}
	}

	private void convertVideoToBitmapList2() {
		try {
			long start = System.currentTimeMillis();
			int width = 320;
			int height = 240;

			// extract video to bitmap

			MainActivity.openFile("/sdcard/myvideo.mp4");

			Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),
					R.drawable.test0);
			lBitmap = new ArrayList<Bitmap>();
			lBitmap.clear();
			for (int i = 0; i < 200; i++) {
				System.out.println(i);
				if (i % 10 == 0) {
					Bitmap bm = mBitmap.copy(Bitmap.Config.ARGB_8888, true);
					MainActivity.drawFrame(bm, width, height, 1);
					lBitmap.add(bm);
				} else {
					MainActivity.drawFrame(mBitmap, width, height, 0);
				}

			}

			long stop = System.currentTimeMillis();
			System.out.println(stop - start);

		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	private void convertVideoToBitmapList3() {
		try {
			long start = System.currentTimeMillis();
			FFmpeg ff = FFmpeg.getInstance();
			ff.openFile("/sdcard/myvideo.mp4");
			int width = ff.getWidth();
	        int height = ff.getHeight();
	        ff.setScreenSize(width, height);
	        ff.prepareResources();
	        lBitmap = new ArrayList<Bitmap>();
	        for(int i=0;i<120;i++){
	        	if(i%6 != 0){
	        		byte[] nativePixels = ff.getNextDecodedFrame();
	        	}else{
			        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
			        byte[] nativePixels = ff.getNextDecodedFrame();
			        ByteBuffer buffer = ByteBuffer.wrap(nativePixels);
			        bitmap.copyPixelsFromBuffer(buffer);
			        lBitmap.add(bitmap);
	        	}
		        
	        }
			long stop = System.currentTimeMillis();
			System.out.println(stop - start);

		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}
	
	private void convertVideoToBitmapList() {
		try {
			long start = System.currentTimeMillis();
			int width = 320;
			int height = 240;

			// extract video to bitmap
			MediaMetadataRetriever mRetriever = new MediaMetadataRetriever();
			mRetriever.setDataSource("/sdcard/myvideo.mp4");

			lBitmap = new ArrayList<Bitmap>();

			for (int i = 0; i < 20; i++) {
				Bitmap bm = mRetriever.getFrameAtTime(330000 * i,MediaMetadataRetriever.OPTION_CLOSEST_SYNC);
				lBitmap.add(bm);

			}
			long stop = System.currentTimeMillis();
			System.out.println(stop - start);

		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
	}

	private class LoadViewTask extends AsyncTask<Void, Integer, Void> {
		ProgressDialog progressDialog;

		@Override
		protected void onPreExecute() {
			progressDialog = ProgressDialog.show(MakeGIF_v2.this, "Loading...",
					"Loading GIF preview, please wait...", false, false);
		}

		@Override
		protected Void doInBackground(Void... arg0) {
			convertVideoToBitmapList2();
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			// close the progress dialog
			progressDialog.dismiss();
			Intent intent = new Intent(MakeGIF_v2.this, PreviewGIF.class);
			Images.listImage = lBitmap;
			startActivity(intent);
			finish();
		}
	}

	private class CameraTime extends Thread {
		public void run() {
			while (true) {
				MakeGIF_v2.this.runOnUiThread(new Runnable() {

					@Override
					public void run() {
						System.out.println(camera_time);
						tv_time.setText(String.valueOf(camera_time));
					}
				});

				try {
					sleep(time_sleep);

					camera_time--;
					if (camera_time == -1) {
						camera_time = 20;
						mediaRecorder.stop(); // stop the recording
						releaseMediaRecorder(); // release the MediaRecorder
												// object

						MakeGIF_v2.this.runOnUiThread(new Runnable() {

							@Override
							public void run() {
								progressDialog = ProgressDialog.show(
										MakeGIF_v2.this, "Loading...",
										"Loading GIF preview, please wait...",
										false, false);
							}

						});
						convertVideoToBitmapList3();
						MakeGIF_v2.this.runOnUiThread(new Runnable() {

							@Override
							public void run() {
								progressDialog.dismiss();
								Intent intent = new Intent(MakeGIF_v2.this,
										PreviewGIF.class);

								Images.listImage = lBitmap;
								startActivity(intent);
								MakeGIF_v2.this.finish();
							}

						});
						break;
					}
				} catch (Exception e) {
					e.printStackTrace();
					this.interrupt();
				}
			}
		}

	}

}